#include "simu_mcu582.h"

#define WIN_UART_BUF_SIZE 2048
extern ZqRingBuf* uart_tx_buf[4];
extern ZqRingBuf* uart_rx_buf[4];

static void SimuUartThreadFunc(void* port_num)
{
    uint8_t port = (uint8_t)port_num;
    uint32_t len = 0;
    ZqSimuUartHandle* simu_uart = &(zq_simu_uart_handle[port]);
    HANDLE h = (simu_uart->uart) ? simu_uart->uart : simu_uart->pipe_read; // 使用串口还是管道模拟
    uint8_t rx_buf[WIN_UART_BUF_SIZE];
    while (1) {
        BOOL b = ReadFile(h, rx_buf, WIN_UART_BUF_SIZE, &len, NULL);
        if (b && 0 < len) {//读成功并且数据大小大于0
            ZqRingBufWrite(uart_rx_buf[port], rx_buf, len);
        }
        Sleep(15);
    }
}

void HalUartInit(uint8_t port, int baudrate, ZqRingBuf* tx_buf, ZqRingBuf* rx_buf)
{
    DCB dcb;
    COMMTIMEOUTS CommTimeouts;
    ZqSimuUartHandle* simu_uart = &(zq_simu_uart_handle[port]);
    if (simu_uart->uart_port_str == NULL && simu_uart->pipe_read == NULL) return; // 串口未配置
    uart_tx_buf[port] = tx_buf;
    uart_rx_buf[port] = rx_buf;
    if (simu_uart->rx_thread != NULL) return; // 已经被占用

    simu_uart->mutex = CreateMutex(NULL, FALSE, NULL);

    if (simu_uart->pipe_read) { // 使用管道模拟
        // 启动模拟接受线程
        simu_uart->rx_thread = _beginthread(SimuUartThreadFunc, 0, (void*)port);
        assert(INVALID_HANDLE_VALUE != simu_uart->rx_thread);
        return;
    }

    //int wcom_port_len = strlen(simu_uart->uart_port_str) + 1;
    //assert(wcom_port_len < 64);
    //wchar_t wcom_port[32] = { 0 };
    //mbstowcs(wcom_port, simu_uart->uart_port_str, wcom_port_len);
    //打开串口
    int wcom_port_len = strlen(simu_uart->uart_port_str);
    assert(wcom_port_len < 31);
    char port_str[32] = { 0 };
    if (wcom_port_len <= 4) strcpy(port_str, simu_uart->uart_port_str);     // if < COM9
    else sprintf(port_str, "\\\\.\\%s", simu_uart->uart_port_str);          // windows 设备要求> com9, 使用\\.\comxx这种格式
    wchar_t wcom_port[32] = { 0 };
    wcom_port_len = strlen(port_str) + 1;
    mbstowcs(wcom_port, port_str, wcom_port_len);
    //使用串口模拟, 打开串口
    simu_uart->uart = CreateFile(
        wcom_port,                      //串口名称
        GENERIC_READ | GENERIC_WRITE,	//可读、可写   				 
        0,            // No Sharing                               
        NULL,         // No Security                              
        OPEN_EXISTING,// Open existing port only                     
        FILE_ATTRIBUTE_NORMAL,            // Non Overlapped I/O                           
        NULL);        // Null for Comm Devices
    if (INVALID_HANDLE_VALUE == simu_uart->uart) {
        DWORD err = GetLastError();
        return;
    }

    // 设置读写缓存大小
    if (!SetupComm(simu_uart->uart, WIN_UART_BUF_SIZE, WIN_UART_BUF_SIZE)) assert(0);

    //设定读写超时
    CommTimeouts.ReadIntervalTimeout = MAXDWORD;//读间隔超时 - 立刻返回
    CommTimeouts.ReadTotalTimeoutMultiplier = 0;//读时间系数
    CommTimeouts.ReadTotalTimeoutConstant = 0;//读时间常量
    CommTimeouts.WriteTotalTimeoutMultiplier = 0;//写时间系数
    CommTimeouts.WriteTotalTimeoutConstant = 200;//写时间常量 - 写总超时
    if (!SetCommTimeouts(simu_uart->uart, &CommTimeouts)) assert(0);

    //设置串口状态属性
    GetCommState(simu_uart->uart, &dcb);//获取当前
    dcb.BaudRate = baudrate; //波特率
    dcb.ByteSize = 8; //每个字节有效位数
    dcb.Parity = NOPARITY; //无奇偶校验位
    dcb.StopBits = ONESTOPBIT; //一个停止位
    // 关键：禁用所有流控制
    dcb.fOutxCtsFlow = FALSE;
    dcb.fOutxDsrFlow = FALSE;
    dcb.fDtrControl = DTR_CONTROL_DISABLE;
    dcb.fRtsControl = RTS_CONTROL_DISABLE;
    dcb.fInX = FALSE;
    dcb.fOutX = FALSE;
    if (!SetCommState(simu_uart->uart, &dcb)) assert(0);
    // 设置缓冲区
    SetupComm(simu_uart->uart, 4096, 4096);
    // 清空缓冲区
    PurgeComm(simu_uart->uart, PURGE_TXCLEAR | PURGE_RXCLEAR);

    // 启动模拟接受线程
    simu_uart->rx_thread = _beginthread(SimuUartThreadFunc, 0, (void*)port);
    assert(INVALID_HANDLE_VALUE != simu_uart->rx_thread);

    return;
}
__HIGH_CODE
void HalUartSend(uint8_t port)
{
    unsigned int ret = 0;
    uint8_t tx_buf[WIN_UART_BUF_SIZE];
    int len = ZqRingBufRead(uart_tx_buf[port], tx_buf, WIN_UART_BUF_SIZE);

    HANDLE h = (zq_simu_uart_handle[port].uart) ? zq_simu_uart_handle[port].uart : zq_simu_uart_handle[port].pipe_write; // 使用串口还是管道模拟
    if (!WriteFile(h, tx_buf, len, &ret, NULL)) {
        int err = GetLastError();
        ZQLOG("uart write error %d", err);
    }
    ZqRingBufFlush(uart_tx_buf[port], len);
}
